package com.navinfo.collect.library.map.layers;


import android.util.Log;

import com.navinfo.collect.library.utils.GeometryTools;

import org.locationtech.jts.geom.Polygon;
import org.oscim.backend.CanvasAdapter;
import org.oscim.core.GeoPoint;
import org.oscim.core.Point;
import org.oscim.layers.vector.VectorLayer;
import org.oscim.layers.vector.geometries.JtsDrawable;
import org.oscim.layers.vector.geometries.LineDrawable;
import org.oscim.layers.vector.geometries.PointDrawable;
import org.oscim.layers.vector.geometries.PolygonDrawable;
import org.oscim.layers.vector.geometries.Style;
import org.oscim.map.Map;
import org.oscim.utils.GeoPointUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/*
 *com.nmp.map.layer
 *zhjch
 *2021/9/28
 *9:28
 *说明（）
 */
public class NIPolygonLayer extends VectorLayer {
    private JtsDrawable mDrawable;
    protected Style mStyle;
    protected final ArrayList<GeoPoint> mPoints = new ArrayList<>();
    private boolean isClose = true;

    public NIPolygonLayer(Map map, Style style) {
        super(map);
        mStyle = style;
    }

    public NIPolygonLayer(Map map, int lineColor, float lineWidth) {
        this(map, Style.builder()
                .fixed(true)
                .strokeColor(lineColor)
                .strokeWidth(lineWidth)
                .build());
    }

    public NIPolygonLayer(Map map, int lineColor) {
        this(map, lineColor, 2);
    }

    /**
     * 设置polygon的点位
     */
    public void setPolygonString(List<GeoPoint> pointList, boolean isClose) {

    }

    /**
     * 移除正在绘制的的图形
     */
    public void removeCurrentDrawable() {
        if (mDrawable != null) {
            remove(mDrawable);
            mDrawable = null;
        }
    }


    /**
     * @param :
     * @return :
     * @method : getPolygon
     * @Author : xiaoxiao
     * @Describe : 获取当前polygon的wkt
     * @Date : 2018/12/18
     */
    public Polygon getPolygon() {
        if (mPoints == null || mPoints.size() < 3) {
            return null;
        }
        if (mPoints.get(0).distance(mPoints.get(mPoints.size() - 1)) > 0) {
            mPoints.add(mPoints.get(0));
        }
        return GeometryTools.createPolygon(mPoints);
    }


    private final Point mPoint1 = new Point();
    private final Point mPoint2 = new Point();


    public void setStyle(Style style) {
        mStyle = style;
    }

    public void clearPath() {
        if (!mPoints.isEmpty())
            mPoints.clear();

        updatePoints();
    }

    public void setPoints(Collection<? extends GeoPoint> pts) {
        mPoints.clear();
        mPoints.addAll(pts);
        updatePoints();
    }

    public void addPoint(GeoPoint pt) {
        mPoints.add(pt);
        updatePoints();
    }

    public void addPoint(int latitudeE6, int longitudeE6) {
        mPoints.add(new GeoPoint(latitudeE6, longitudeE6));
        updatePoints();
    }

    public void addPoints(Collection<? extends GeoPoint> pts) {
        mPoints.addAll(pts);
        updatePoints();
    }

    private void updatePoints() {
        Log.e("jingo 1", mPoints.toString());

        if (mPoints.size() > 2 && !GeometryTools.createGeometry(mPoints.get(0)).equals(GeometryTools.createGeometry(mPoints.get(mPoints.size() - 1)))) {
            mPoints.add(mPoints.get(0));
        }
        Log.e("jingo 2", mPoints.toString());
        synchronized (this) {
            removeCurrentDrawable();
            if (mPoints.size() == 2) {
                mDrawable = new LineDrawable(mPoints, mStyle);
                add(mDrawable);
            } else if (mPoints.size() > 3) {
                //绘制报错，现用线代替，后续解决
                // mDrawable = new PolygonDrawable(mPoints, mStyle);
                mDrawable = new LineDrawable(mPoints, mStyle);
                add(mDrawable);
            }else {
                mDrawable = new PointDrawable(mPoints.get(0),mStyle);
                add(mDrawable);
            }
            Log.e("jingo 3", mPoints.toString());

            if (mPoints.size() > 3 && mPoints.get(0) == mPoints.get(mPoints.size() - 1)) {
                mPoints.remove(mPoints.size() - 1);
            }

        }
        Log.e("jingo 4", mPoints.toString());
        mWorker.submit(0);
    }

    public List<GeoPoint> getPoints() {
        return mPoints;
    }
//
//    /**
//     * Draw a great circle. Calculate a point for every 100km along the path.
//     *
//     * @param startPoint start point of the great circle
//     * @param endPoint   end point of the great circle
//     */
//    public void addGreatCircle(GeoPoint startPoint, GeoPoint endPoint) {
//        synchronized (mPoints) {
//
//            /* get the great circle path length in meters */
//            double length = startPoint.sphericalDistance(endPoint);
//
//            /* add one point for every 100kms of the great circle path */
//            int numberOfPoints = (int) (length / 100000);
//            if (numberOfPoints == 0)
//                return;
//
//            addGreatCircle(startPoint, endPoint, numberOfPoints);
//        }
//    }

//    /**
//     * Draw a great circle.
//     *
//     * @param startPoint     start point of the great circle
//     * @param endPoint       end point of the great circle
//     * @param numberOfPoints number of points to calculate along the path
//     */
//    public void addGreatCircle(GeoPoint startPoint, GeoPoint endPoint,
//                               final int numberOfPoints) {
//        /* adapted from page
//         * http://compastic.blogspot.co.uk/2011/07/how-to-draw-great-circle-on-map-in.html
//         * which was adapted from page http://maps.forum.nu/gm_flight_path.html */
//
//        GeomBuilder gb = new GeomBuilder();
//
//        /* convert to radians */
//        double lat1 = startPoint.getLatitude() * Math.PI / 180;
//        double lon1 = startPoint.getLongitude() * Math.PI / 180;
//        double lat2 = endPoint.getLatitude() * Math.PI / 180;
//        double lon2 = endPoint.getLongitude() * Math.PI / 180;
//
//        double d = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin((lat1 - lat2) / 2), 2)
//                + Math.cos(lat1) * Math.cos(lat2)
//                * Math.pow(Math.sin((lon1 - lon2) / 2), 2)));
//        double bearing = Math.atan2(
//                Math.sin(lon1 - lon2) * Math.cos(lat2),
//                Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
//                        * Math.cos(lat2)
//                        * Math.cos(lon1 - lon2))
//                / -(Math.PI / 180);
//        bearing = bearing < 0 ? 360 + bearing : bearing;
//
//        for (int i = 0, j = numberOfPoints + 1; i < j; i++) {
//            double f = 1.0 / numberOfPoints * i;
//            double A = Math.sin((1 - f) * d) / Math.sin(d);
//            double B = Math.sin(f * d) / Math.sin(d);
//            double x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2)
//                    * Math.cos(lon2);
//            double y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2)
//                    * Math.sin(lon2);
//            double z = A * Math.sin(lat1) + B * Math.sin(lat2);
//
//            double latN = Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
//            double lonN = Math.atan2(y, x);
//
//            gb.point(latN / (Math.PI / 180), lonN / (Math.PI / 180));
//        }
//
//        setPolygon(gb.toLineString());
//    }

//    public void setPolygon(Polygon path) {
//        synchronized (this) {
//            if (mDrawable != null)
//                remove(mDrawable);
//            mDrawable = new PolygonDrawable(path, mStyle);
//            add(mDrawable);
//
//            mPoints.clear();
//            for (int i = 0; i < path.getNumPoints(); i++) {
//                Coordinate c = path.getCoordinateN(i);
//                mPoints.add(new GeoPoint(c.y, c.x));
//            }
//        }
//        mWorker.submit(0);
//    }

//    public void setLineString(double[] lonLat) {
//        synchronized (this) {
//            if (mDrawable != null)
//                remove(mDrawable);
//            mDrawable = new PolygonDrawable(lonLat, mStyle);
//            add(mDrawable);
//
//            mPoints.clear();
//            for (int i = 0; i < lonLat.length; i += 2)
//                mPoints.add(new GeoPoint(lonLat[i + 1], lonLat[i]));
//        }
//        mWorker.submit(0);
//    }

    @Override
    public synchronized boolean contains(float x, float y) {
        // Touch min 20 px at baseline mdpi (160dpi)
        double distance = Math.max(20 / 2 * CanvasAdapter.getScale(), mStyle.strokeWidth);
        for (int i = 0; i < mPoints.size() - 1; i++) {
            if (i == 0)
                mMap.viewport().toScreenPoint(mPoints.get(i), false, mPoint1);
            else {
                mPoint1.x = mPoint2.x;
                mPoint1.y = mPoint2.y;
            }
            mMap.viewport().toScreenPoint(mPoints.get(i + 1), false, mPoint2);
            if (GeoPointUtils.distanceSegmentPoint(mPoint1.x, mPoint1.y, mPoint2.x, mPoint2.y, x, y) <= distance)
                return true;
        }
        return false;
    }
}